/* 
自定义Promise
*/
((window) => {


    const PENDING = "pending"
    const FULFILLED = 'fulfilled'
    const REJECTED = 'rejected'



    /**
     * 构造函数
     * @param  excutor 执行器函数  
     */


    function Promise(excutor) {
        /* 初始化3个属性 */
        // 1.状态:pending/fulfilled//rejected ==>state
        // 2.结果数据:undefined/value/reason ==> data
        // 3.保存待处理回调的数组:[{resolved(){},rejected(){}},{resovled(){},rejected(){}}]

        this.state = PENDING;

        this.data = undefined;

        this.callbacks = [];

        const self = this;


        function resolve(value) {

            if (self.state !== PENDING) return

            self.state = FULFILLED

            self.data = value

            if (self.callbacks.length > 0) {
                setTimeout(() => {
                    self.callbacks.forEach(callbackObj => callbackObj.resolve(value))
                }, 0);

            }
        }

        function reject(reason) {

            if (self.state !== PENDING) return

            self.state = REJECTED

            self.data = reason

            if (self.callbacks.length > 0) {
                setTimeout(() => {
                    self.callbacks.forEach(callbackObj => callbackObj.rejected(reason))
                }, 0);
            }
        }

        try {
            /* 在构造函数中,会立即同步调用执行器函数,并传入resolve和reject 两个函数 */
            excutor(resolve, reject)
        } catch (error) {
            reject(error)
        }
    }


    /**
     * 指定成功和失败的回调,并返回一个新的promise
     * @param {*} onRsolved 成功的回调=>用于得到成功的value 
     * @param {*} onRejected 失败的回调=>用于得到失败的reason
     */
    Promise.prototype.then = function (onRsolved, onRejected) {
        // console.log('then()');
        const self = this

        onRsolved = typeof onRsolved === 'function' ? onRsolved : value => value

        onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason }

        return new Promise((resolve, reject) => {

            function handle(callback) {
                try {
                    const result = callback(self.data)
                    if (result instanceof Promise) {
                        result.then(
                            value => resolve(value),
                            reason => reject(reason)
                        )
                    } else {
                        resolve(result)
                    }
                } catch (error) {
                    reject(error)
                }
            }




            if (self.state === FULFILLED) {
                setTimeout(() => {
                    handle(onRsolved)
                }, 0);

            } else if (self.state === REJECTED) {
                setTimeout(() => {
                    handle(onRejected)
                }, 0);
            } else {
                self.callbacks.push({
                    resolved: () => handle(onRsolved),
                    rejected: () => handle(onRejected)
                })
            }
        })
    }


    /**
     * 失败的回调=>用于得到失败的reason
     * @param {*} onRejected 
     */
    Promise.prototype.catch = function (onRejected) {
        return this.then(value => value, onRejected)
    }

    /**
     * 返回一个成功的promise,value为指定的value
     * @param {*} value 
     */
    Promise.resolve = function (value) {
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(
                    value => resolve(value),
                    reason => reject(reason)
                )
            } else {
                resolve(value)
            }
        })
    }

    /**
     * 返回一个失败的promise,reason为指定的reason
     * @param {*} reason 
     */
    Promise.reject = function (reason) {
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }


    /**
     * 返回一个promise, 如果promises都成功, 它才成功, 成功的value为所有value组成的数组, 只要有一个失败, 那它就失败了
     * @param {*} promises 
     */
    Promise.all = function (promises) {

        const values = []

        let resolvedCount = 0
        return new Promise((resolve, reject) => {
            promises.forEach((p, index) => {
                    p.then(
                        value=>{
                            
                            values[index] = value

                            resolvedCount +=1

                            if(resolvedCount === promises.length)
                            resolve(values)
                        },reason=>{
                            reject(reason)
                        }
                    )
                    })
                })
            }


        /**
         * 返回一个promise, 由第一个完成的promie来决定它的结果
         * @param {*} promises 
         */
        Promise.race = function (promises) {
            return new Promise((resolve, reject) => {
                promises.forEach(p => {
                    p.then(
                        value => resolve(value),
                        reason => reject(reason)
                    )
                })
            })
        }

        /**
         * 返回一个promise, 当所有promise都完成时它就成功, value值为所有promise的value或reason组成的数组
         * @param {*} promises 
         */
        Promise.allSettled = function (promises) {

            const results = []

            let settledCount = 0


            return new Promise((resolve) => {
                promises.forEach((p, index) => {
                    p.then(
                        value => {
                          // 保存当前成功value和成功状态的对象
                          results[index] = {status: 'fulfilled', value}
                          settledCount++
                          if (settledCount===promises.length) {
                            resolve(results)
                          }
                        },
                        reason => {
                          // 保存当前失败的reason和失败状态的对象
                          results[index] = {status: 'rejected', reason}
                          settledCount++
                          if (settledCount===promises.length) {
                            resolve(results)
                          }
                        }
                      )     
                })
            })
        }


        /* 返回一个迟延指定时间才成功的promise */
        Promise.resolveDelay = function (value, delay) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resovle(value)
                }, delay);
            })
        }

        /* 返回一个迟延指定时间才失败的promise */
        Promise.rejectDelay = function (reason, delay) {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    reject(reason)
                }, delay);
            })
        }

        window.Promise = Promise
    }) (window);